/*
 * ValidationCheck.cpp
 *
 *  Created on: 14 mars 2012
 *      Author: jocelyn
 */

#include "ValidationCheck.h"


using namespace std;



static void VerifyContent(string nameElement, Item * items, DTD * dtd)
{
/*
 * On vérifie que les données dans la  balise sont correctes :
 * On vérifie Le type de données s'il est simple ou si une seule balise est contenue dans l'élément ( selon la règle )
 * On vérifie les types de données + les balises si il y a un type énuméré. On ne vérifie pas le contenu des balises de l'élement à ce niveau
 * mais au niveau de récursicvité inférieure
 * Si pas de règle pour l'élément on renvoie un erreur
 */

	  vector<Item*>::iterator itContent = ((Element*)items)->getItems()->begin();
	  map<string,DeclElement*> *  listElement = dtd->getMapElement();
	  map<string,DeclElement*>::iterator itDtd = listElement->begin();

	  int errCount = 0;
	  for(itContent ; itContent != ((Element*)items)->getItems()->end() ; itContent++)
	  {

		  itDtd = listElement->find(nameElement);
		  if(itDtd == listElement->end()){
			  cout << "Pas de règle trouvée pour l'élément " << nameElement << endl;
			  break;
		  }


				  /*
				   * Plusieurs cas : L'élement n'a pas de fils, et ne contient que du texte
				   * L'élement a un ou plusieurs élement fils.
				   */
				  ContentDTD * content = itDtd->second->getContentDTD();
				  vector<ContentDTD*> listeFils = content->getFils();
				  Element * temp = dynamic_cast<Element *>(*itContent);

				  if (listeFils.size() == 0)
				  {
					  //non fils

					  if(temp->getItems()->size() == 0)
					  {
						  cout << "L'élement " << nameElement << " est composé de texte autorisé" << endl;
					  }
					  else
					  {
						  cout << "L'élément " << nameElement << " est composé de balises non déclarées dans la DTD." << endl ;
						  errCount ++;
					  }
				  }
				  else
				  {
					  // list fils non vide
					string lastElement = "";
					unsigned int pos = 0;

					//cout<<temp->getItems()->size()<<endl;





					for(unsigned int i = 0; i < temp->getItems()->size()-1; i++){


						//name for the child
						vector<Item*>& vecRef = (vector<Item*>&)(*temp->getItems());
						Item *itemp = vecRef[i];
					    string filsname;
					    if ((itemp->getName()) == NULL) return;
					    else filsname = *(itemp->getName());
					    cout<< *(itemp->getName())<<endl<<endl<<endl<<endl<<endl;
					    cout<<filsname<<endl;
/*
						vector<Item *> lstItem = *(temp ->getItems());

						Item* itemp = (Item *) (lstItem[i]);

						string filsname = string(*(itemp->getName()));
						//strcpy(filsname.c_str(),(itemp->getName())->c_str());
*/
						//verify the rules

						//mixed
						if(content->getType()=="Mixte_NONAST"){
							//1 occurence
							for(int j=0; j< content->getFils().size();j++)
							{

							}

							return;
						}

						if(content->getType()=="Mixte_AST"){
							//0+ occurences

							return;
						}


						//sequence
						Sequence * seq =dynamic_cast<Sequence *>(listeFils[0]);
						if(seq){

							vector<ContentDTD*> vfils = seq->getFils();
							if(lastElement == ""){pos = 0;}
							else{
								for(int j = 0; j < vfils.size() - 1; j ++){
									ItemDTD * iiseq =(ItemDTD *)vfils[j];
									if(iiseq->getName()==lastElement){
										pos = j + 1;
									}
								}


							}


								//item
								ItemDTD * iseq =(ItemDTD *)vfils[pos];

								if(filsname != iseq->getName()){
									cout<< "wrong element in sequence : "<<nameElement<<endl;
									return;
								}



						}else{
						//choix
							Choix * choix = dynamic_cast<Choix *>(listeFils[0]);
							bool absence = true;
							if(choix){
								vector<ContentDTD * > cfils = choix->getFils();

								for(int j =0;j < cfils.size(); j++){
									ItemDTD * ifils = (ItemDTD*) cfils[j];
									if(ifils->getName()==filsname){
										absence = false;
									}
								}

								if(absence){
									cout << "missing elements in "<< nameElement << endl;

									return;
								}
							}
						}


						lastElement = filsname;
				    }
				  }

	  }
	  cout << "l'element '" << nameElement << "' est valide." << endl;
}

static void VerifyAttributs(string nameElement, vector<Attribut*> * attributs, DTD * dtd)
{
/*
 * On commence par chercher la règle DTD associée à l'élément XLM passé ne paramètre
 * On vérifie que l'attribut de l'element est iben présent dans les règles et que son type est CDATA
 */
	  vector<Attribut*>::iterator itAtt = attributs->begin();
	  map<string,AttributDTD*> * listAttributs = dtd->getAttMapByName(nameElement);
	  map<string,AttributDTD*>::iterator itDtd = listAttributs->begin();

	  for(itAtt ; itAtt != attributs->end() ; itAtt++)
	  {
		  for(itDtd ; itDtd != listAttributs->end() ; itDtd++)
		  {
			  //itAtt->
			  if(*((*itAtt)->getName()) == itDtd->second->getName() )
			  {
				  break;
			  }
		  }
		  if(itDtd == listAttributs->end())
		  {
			  cout << "error: attribut '" << (*itAtt)->getName() << "' de l'element '" << nameElement << "' ne correspond pas au DTD" << endl;
			  return;
		  }
	  }
	  cout << "attributs de l'element '" << nameElement << "' sont valides" << endl;

}


static void parcoursArbre(vector<Item* > * items, DTD * dtd)
{
	for(int unsigned i=0;i<items->size();i++)
	{
		vector<Item*>& vecRef = *items;
		Item *theItem = vecRef[0];
		string nameElement = *(theItem->getName());
		ContentElement* item;
		item = dynamic_cast<ContentElement*>(theItem);

		if (item)
		{
		    // Traitement Contentélément
			VerifyAttributs(nameElement, (item)->getAttributs(),dtd);

			VerifyContent(nameElement,item, dtd);
			if((item)->getItems()->size()>0){
			//parcoursArbre((item)->getItems(), dtd);
			}
		}
		EmptyElement* item2;
		item2 = dynamic_cast<EmptyElement*>(theItem);

		if (item)
		{
		    // Traitement EmptyElement
			VerifyAttributs(nameElement,((EmptyElement*)theItem)->getAttributs(),dtd); //problem here : must verify that the empty element has the right to be empty.

		}
		else
		{
			//Le reste = DATA
			cout << "DATA";
		}

	}
}


static void VerifyCardinality()
{
/*
 * On vérifie que le contenu a la bonne cardinalité :
 * * zero or more
 * + minimum 1
 * rien : only one
 */
}


void VefifyConditions(XMLArbre * arbre, DTD * dtd)
{
	/*
	 * Principe de l'algo : On parcours l'arbre XML de façon récursive, pour chaque element on teste si il correspond à la DTD.
	 * On s'arrete une fois en bas de l'arbre : On vérifie que c'est bon et on remonte d'un cran, a chaque cran ( apres appel récursif)
	 * on vérifie que les balises respectent bien les règles de la DTD.
	 * Plusieurs cas :
	 * Vérification d'attributs : On vérifie les rèlges concernant les attributs
	 * Vérification de contenu : On vérifie le contenu ( balise contenu ou contenu ( string ) )
	 * Si le contenu est correct on vérifie sa cardinalité.
	 */
	Element * element = arbre->getRacine();
	vector<Attribut*> * attributs = element->getAttributs();
	VerifyAttributs(*(element->getName()), attributs, dtd);
	vector<Item* > * items = element->getItems();
	parcoursArbre(items, dtd);
}





